package persistencia.csv;

import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;
import java.util.regex.Pattern;

import persistencia.IAlmacen;
import persistencia.IEnsamblador;
import persistencia.IGondola;
import persistencia.IProducto;
import persistencia.compartido.IteradorDeEntidades;
import persistencia.compartido.Tipo;
import persistencia.excepciones.EscritorIncompatible;
import persistencia.excepciones.LectorIncompatible;

import compartido.IEntidad;

public class GondolaCSV implements IGondola {

	protected EncabezadoCSV encabezado;
	protected Map<String,ProductoCSV> registros;
	protected IEnsamblador ensamblador;
	protected IAlmacen almacen;
	
	protected String directorio; 
	protected Pattern patron;
	protected boolean sucia;
	protected static String separadores = ",";
	
	protected String armarNombreArchivo(String directorio, String tipo) {
		return directorio+"/"+tipo+".csv";
	}
	
	protected GondolaCSV(File directorio, Tipo<IEntidad> tipo, IEnsamblador ensamblador, IAlmacen almacen) {
		this.directorio = directorio.getPath();
		this.registros = new TreeMap<String,ProductoCSV>();
		this.ensamblador = ensamblador;
		this.almacen = almacen;
		this.patron = Pattern.compile(separadores);
		this.sucia = true;
		
		try {
			String[] linea = null;
			String archivo = armarNombreArchivo(this.directorio, tipo.getNombre());
			LectorCSV lector = new LectorCSV(archivo, separadores);
			linea = lector.leer();
			if (linea != null) {
				encabezado = new EncabezadoCSV(tipo.getNombre());
				for (int i=0; i<linea.length; i++)
					encabezado.agregar(linea[i]);
				linea = lector.leer();
			}
			while (linea != null) {
				ProductoCSV registro = new ProductoCSV(encabezado,linea);
				registros.put(registro.get(0), registro);
				linea = lector.leer();
			}
			sucia = false;
		} catch (IOException e) {
			try {
				IProducto p = ensamblador.getDummy(tipo);
				encabezado = new EncabezadoCSV(tipo.getNombre());
				
				Iterator<String> campo = p.getNombreDeIngredientes();
				while (campo.hasNext())
					encabezado.agregar(campo.next());
				
			} catch (EscritorIncompatible e1) {
				encabezado = null;
			}
			
		}
	}
	
	public void configurar(IEntidad ejemplo) {
		ProductoCSV p = null;
		try {
			p = (ProductoCSV) ensamblador.escribir(ejemplo,almacen);
			
			if ((encabezado != null) && (getEncabezado().compareTo(p.getEncabezado()) != 0)) {
				registros.clear();
				sucia = true;
			}
			this.encabezado = p.getEncabezado();
			
			
			
		} catch (EscritorIncompatible e) {
			p = null;
		}
		
	}
	
	public EncabezadoCSV getEncabezado() {
		return encabezado;
	}
	
	@Override
	public boolean estaSucia() {
		return sucia;
	}
	
	@Override
	public String getNombre() {
		return encabezado.getTipo();
	}

	@Override
	public boolean agregar(IEntidad nueva) {
		boolean esNuevo = !registros.containsKey(nueva.getIdentificador());
		if (esNuevo) {
			IProducto p;
			try {
				p = ensamblador.escribir(nueva,almacen);

				if (p instanceof ProductoCSV) {
					ProductoCSV producto = (ProductoCSV)p;
					registros.put(producto.getNombre(),producto);
					if (encabezado == null)
						encabezado = producto.getEncabezado();
				}
				sucia = true;
			} catch (EscritorIncompatible e) {
				//Si llega aca hay un error en la logica superior.
				esNuevo = false;
			}
		}		
		return esNuevo;
	}
	
	@Override
	public boolean eliminar(IEntidad existente) {
		boolean existe = registros.containsKey(existente.getIdentificador());
		if (existe) {
			registros.remove(existente.getIdentificador());
			sucia = true;
		}
		return existe;
	}
	
	@Override
	public Iterator<IEntidad> getIterator() {
		return new IteradorDeEntidades<ProductoCSV>(
				registros.values().iterator(),this.ensamblador,this.almacen);
	}
	
	@Override
	public boolean modificar(IEntidad modificada) {
		boolean existe = registros.containsKey(modificada.getIdentificador());
		if (existe) {
			IProducto p;
			try {
				p = ensamblador.escribir(modificada,almacen);

				if (p instanceof ProductoCSV) {
					ProductoCSV producto = (ProductoCSV)p;
					registros.put(producto.getNombre(),producto);
				}
				sucia = true;
			} catch (EscritorIncompatible e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		return false;
	}
	@Override
	public IEntidad obtener(String identificador) {
		IProducto buscado = obtenerProducto(identificador);
		IEntidad traducido = null;
		if (buscado != null)
			try {
				traducido = ensamblador.leer(buscado,almacen);
			} catch (LectorIncompatible e) {
				traducido = null;
			}
		return traducido;
	}
	
	public ProductoCSV obtenerProducto(String identificador) {
		return registros.get(identificador);
	}
	
	@Override
	public Iterator<IEntidad> iterator() {
		return getIterator();
	}
	
	public void guardar() {
		if ( (encabezado != null) && (estaSucia()) ) {
			try {
				String archivo = armarNombreArchivo(directorio,encabezado.getTipo());
				EscritorCSV escritor = new EscritorCSV(archivo, separadores.charAt(0));
				
				escritor.escribir(getEncabezado().getCampos());
				
				for (ProductoCSV p : registros.values())
					escritor.escribir(p.getValores());

				escritor.close();
				
				sucia = false;
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}
